package com.arpa.oms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.arpa.ntocc.common.common.cache.PartyCache;
import com.arpa.ntocc.common.common.exception.ServiceException;
import com.arpa.ntocc.common.common.util.UserUtil;
import com.arpa.oms.domain.entity.*;
import com.arpa.oms.domain.enums.OmsOutboundTypeEnum;
import com.arpa.oms.domain.enums.PurchaseTypeEnum;
import com.arpa.oms.domain.enums.SettlementStatusEnum;
import com.arpa.oms.domain.vo.OmsSaleReturnVO;
import com.arpa.oms.domain.vo.PurchaseVo;
import com.arpa.oms.domain.vo.SaleVO;
import com.arpa.oms.service.*;
import com.arpa.wms.cache.CustomerCache;
import com.arpa.wms.cache.SupplierCache;
import com.arpa.wms.common.util.BigDecimalUtil;
import com.arpa.wms.common.util.OrderIdGeneratorUtil;
import com.arpa.wms.domain.dto.ExpenseDetailSettlementDTO;
import com.arpa.wms.domain.entity.Customer;
import com.arpa.wms.domain.entity.Supplier;
import com.arpa.wms.domain.enums.ExpenseDetailStatusEnum;
import com.arpa.wms.domain.enums.OrderIdPrefixEnum;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.arpa.oms.domain.enums.PayableAndReceivableStatusEnum.NEWS;
import static com.arpa.oms.domain.enums.PayableAndReceivableStatusEnum.PASS;


/**
 * <p>
 * OMS结算管理服务类实现类
 * </p>
 *
 * @author LEO
 * @since 2020-12-21
 */
@Service
@Log4j2(topic = "business")
public class OmsSettlementServiceImpl implements IOmsSettlementService {

    @Resource
    private SupplierCache supplierCache;
    @Resource
    private CustomerCache customerCache;

    @Resource
    private PartyCache partyCache;
    private final IPurchaseService purchaseService;
    private final IOmsPurchaseReturnService omsPurchaseReturnService;
    private final IOmsPayableService omsPayableService;
    private final IOmsPayableDetailService omsPayableDetailService;
    private final IOmsPayableItemService omsPayableItemService;
    private final ISaleService saleService;
    private final IOmsSaleReturnService omsSaleReturnService;
    private final IOmsReceivableService omsReceivableService;
    private final IOmsReceivableDetailService omsReceivableDetailService;
    private final IOmsReceivableItemService omsReceivableItemService;


    public OmsSettlementServiceImpl(IPurchaseService purchaseService,
                                    IOmsPayableService omsPayableService,
                                    IOmsPayableDetailService omsPayableDetailService,
                                    IOmsPayableItemService omsPayableItemService,
                                    IOmsPurchaseReturnService omsPurchaseReturnService,
                                    ISaleService saleService,
                                    IOmsSaleReturnService omsSaleReturnService,
                                    IOmsReceivableService omsReceivableService,
                                    IOmsReceivableDetailService omsReceivableDetailService,
                                    IOmsReceivableItemService omsReceivableItemService) {
        this.purchaseService = purchaseService;
        this.omsPayableService = omsPayableService;
        this.omsPayableDetailService = omsPayableDetailService;
        this.omsPayableItemService = omsPayableItemService;
        this.omsPurchaseReturnService = omsPurchaseReturnService;
        this.saleService = saleService;
        this.omsSaleReturnService = omsSaleReturnService;
        this.omsReceivableService = omsReceivableService;
        this.omsReceivableDetailService = omsReceivableDetailService;
        this.omsReceivableItemService = omsReceivableItemService;
    }

    /**
     * 生成OMS付款信息
     * 采购单、采购退货单，生成入库单后调用此方法生成付款信息。
     * 原始单据如果已付款，则生成应付明细的同时，生成付款单及付款单明细，已结算金额为已付款金额。
     *
     * @param omsInbound 入库单信息{@link OmsInbound}
     */
    @Override
    public void generatePayment(final OmsInbound omsInbound) {
        //普通采购
        if (StrUtil.equalsAny(omsInbound.getType(),PurchaseTypeEnum.NORMAL.getValue(),PurchaseTypeEnum.PURCHASERETURNS.getValue())) {
            //获取采购单号
            String sourceCode = omsInbound.getSourceCode();
            if (StrUtil.isBlank(sourceCode)) {
                log.error("入库单【{}】来源单号为空，不产生费用记录", omsInbound.getCode());
                return;
            }

            //供应商CODE
            String supplierCode = "";
            if (PurchaseTypeEnum.NORMAL.getValue().equals(omsInbound.getType())) {
                PurchaseVo purchaseVo = purchaseService.getByCode(sourceCode);
                if (null == purchaseVo) {
                    log.error("入库单【{}】来源采购单【{}】为空，不产生费用记录", omsInbound.getCode(), sourceCode);
                    return;
                }
                supplierCode = purchaseVo.getSupplierCode();
            }

            if (PurchaseTypeEnum.PURCHASERETURNS.getValue().equals(omsInbound.getType())) {
                OmsPurchaseReturn omsPurchaseReturn = omsPurchaseReturnService.getOne(new QueryWrapper<OmsPurchaseReturn>().lambda().eq(OmsPurchaseReturn::getCode, sourceCode));
                if (null == omsPurchaseReturn) {
                    log.error("入库单【{}】来源采购退货单【{}】为空，不产生费用记录", omsInbound.getCode(), sourceCode);
                    return;
                }
                supplierCode = omsPurchaseReturn.getSupplierCode();
            }
            if (StrUtil.isBlank(supplierCode)) {
                log.error("入库单【{}】采购供应商为空，不产生费用记录", omsInbound.getCode());
                return;
            }
            //供应商信息
            Map<String, Object> supplierMap = supplierCache.get(supplierCode);
            //获取供应商信息
            Supplier supplier = BeanUtil.mapToBean(supplierMap, Supplier.class, false);
            if (null == supplier) {
                log.error("入库单【{}】来源采购单供应商【{}】为空，不产生费用记录", omsInbound.getCode(), supplierCode);
                return;
            }
            //获取结算状态
            int isSettlement = supplier.getIsSettlement();
            if (isSettlement == 0) {
                log.error("入库单【{}】来源采购单供应商【{}】为不结算，不产生费用记录", omsInbound.getCode(), supplierCode);
                return;
            }
            //已付款金额
            BigDecimal paymentAmount = omsInbound.getPaymentAmount();
            //欠款金额
            BigDecimal owedAmount = omsInbound.getOwedAmount();


            //应付明细
            OmsPayableDetail omsPayableDetail = new OmsPayableDetail();
            omsPayableDetail.setCode(IdUtil.simpleUUID());

            //没有已付金额，应付明细为未结算
            if (paymentAmount.compareTo(BigDecimal.ZERO) == 0) {
                omsPayableDetail.setStatus(SettlementStatusEnum.UNSETTLED);
            } else {
                //有已付金额，欠款金额大于0，应付明细为部分结算
                if (owedAmount.compareTo(BigDecimal.ZERO) != 0) {
                    omsPayableDetail.setStatus(SettlementStatusEnum.PARTIALLY_SETTLED);
                }
                //有已付金额，欠款金额等于0，应付明细为已结算
                if (owedAmount.compareTo(BigDecimal.ZERO) == 0) {
                    omsPayableDetail.setStatus(SettlementStatusEnum.SETTLED);
                }
            }
            omsPayableDetail.setSourceCode(sourceCode);
            omsPayableDetail.setShipmentCode(omsInbound.getShipmentCode());
            omsPayableDetail.setShipmentName(omsInbound.getShipmentName());
            omsPayableDetail.setBillType(PurchaseTypeEnum.getEnumByValue(omsInbound.getType()));
            omsPayableDetail.setGmtBill(omsInbound.getGmtCreated().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            omsPayableDetail.setSupplierCode(supplierCode);
            omsPayableDetail.setSupplierName(supplier.getName());
            //收款明细总金额=付款金额+欠款金额
            omsPayableDetail.setAmountMoney(omsInbound.getOwedAmount().add(omsInbound.getPaymentAmount()));
            omsPayableDetail.setSettledMoney(omsInbound.getPaymentAmount());
            omsPayableDetail.setWaitingSettledMoney(BigDecimal.ZERO);
            omsPayableDetail.setUnsettledMoney(owedAmount);
            omsPayableDetailService.save(omsPayableDetail);






            //已付款，生成付款单和付款明细
            if (paymentAmount.compareTo(BigDecimal.ZERO) != 0) {
                OmsPayable omsPayable = new OmsPayable();
                omsPayable.setCode(OrderIdGeneratorUtil.generatorOmsOrderId(OrderIdGeneratorUtil.OrderTypeEnum.FK, "",UserUtil.getBranchCode()));
                omsPayable.setShipmentCode(omsInbound.getShipmentCode());
                omsPayable.setShipmentName(omsInbound.getShipmentName());
                omsPayable.setSupplierCode(supplier.getCode());
                omsPayable.setSupplierName(supplier.getName());
                omsPayable.setAmountMoney(paymentAmount);
                omsPayable.setAmountCollected(paymentAmount);
                omsPayable.setStatus(PASS);
                omsPayable.setGmtVerify(LocalDateTime.now());
                omsPayable.setCreatedBy(UserUtil.getCode());
                omsPayable.setCreatedName(partyCache.translate(UserUtil.getCode()));
                omsPayable.setModifiedBy(UserUtil.getCode());
                omsPayable.setModifiedName(partyCache.translate(UserUtil.getCode()));
                omsPayableService.save(omsPayable);

                //收款单明细
                OmsPayableItem payableItem = new OmsPayableItem();
                payableItem.setCode(IdUtil.simpleUUID());
                payableItem.setSourceCode(omsInbound.getSourceCode());
                payableItem.setPayableCode(omsPayable.getCode());
                payableItem.setPayableDetailCode(omsPayableDetail.getCode());
                payableItem.setShipmentCode(omsInbound.getShipmentCode());
                payableItem.setShipmentName(omsInbound.getShipmentName());
                payableItem.setBillType(PurchaseTypeEnum.NORMAL);
                payableItem.setGmtBill(omsInbound.getGmtCreated().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
                payableItem.setSupplierCode(supplierCode);
                payableItem.setSupplierName(supplier.getName());
                //收款明细总金额=付款金额+欠款金额
                payableItem.setAmountMoney(payableItem.getAmountMoney());
                payableItem.setSettledMoney(BigDecimal.ZERO);
                //本次结算金额=付款金额
                payableItem.setThisSettledMoney(omsInbound.getPaymentAmount());
                omsPayableItemService.save(payableItem);
            }



        }
    }

    /**
     * 生成OMS收款信息
     *
     * @param omsOutbound
     */
    @Override
    public void generateReceivable(OmsOutbound omsOutbound) {
        //销售出库、销售退货
        if (StrUtil.equalsAny(omsOutbound.getType(), OmsOutboundTypeEnum.SALE_OUT.getValue(), OmsOutboundTypeEnum.SALE_RETURN.getValue())) {
            //获取销售单、销售退货
            String sourceCode = omsOutbound.getSourceCode();
            if (StrUtil.isBlank(sourceCode)) {
                log.error("出库单【{}】来源单号为空，不产生费用记录", omsOutbound.getCode());
                return;
            }


            //客户code
            String customerCode = "";

            if (StrUtil.equals(omsOutbound.getType(), OmsOutboundTypeEnum.SALE_OUT.getValue())) {
                SaleVO sale = saleService.getByCode(sourceCode);
                if (null == sale) {
                    log.error("出库单【{}】来源单【{}】为空，不产生费用记录", omsOutbound.getCode(), sourceCode);
                    return;
                }
                customerCode = sale.getCustomerCode();
            }
            if (StrUtil.equals(omsOutbound.getType(), OmsOutboundTypeEnum.SALE_RETURN.getValue())) {
                OmsSaleReturnVO omsSaleReturnVO = omsSaleReturnService.getByCode(sourceCode);
                if (null == omsSaleReturnVO) {
                    log.error("出库单【{}】来源单【{}】为空，不产生费用记录", omsOutbound.getCode(), sourceCode);
                    return;
                }
                customerCode = omsSaleReturnVO.getCustomerCode();
            }
            if (StrUtil.isBlank(customerCode)) {
                log.error("出库单【{}】客户为空，不产生费用记录", omsOutbound.getCode());
                return;
            }
            //供应商信息
            Map<String, Object> customerMap = customerCache.get(customerCode);
            //获取供应商信息
            Customer customer = BeanUtil.mapToBean(customerMap, Customer.class, false);
            if (null == customer) {
                log.error("出库单【{}】来源单客户【{}】为空，不产生费用记录", omsOutbound.getCode(), customerCode);
                return;
            }
            //获取结算状态
            int isSettlement = customer.getIsSettlement();
            if (isSettlement == 0) {
                log.error("出库单【{}】来源单客户【{}】不结算，不产生费用记录", omsOutbound.getCode(), customerCode);
                return;
            }

            /**
             * 1、已收=0,欠款>0,总金额=欠款 生成收费明细（未结算）
             * 2、已收=0,欠款<0,总金额=欠款 生成收费明细（未结算）
             * 3、已收>0,欠款>0,总金额=已收+欠款 生成收款单、收费明细（部分结算）
             * 4、已收>0,欠款=0,总金额=已收 生成收款单、收费明细（已结算）
             * 5、已收>0,欠款<0,总金额=已收 生成收款单、收费明细（正）（已结算）、收费明细（负）（未结算）
             * 6、已收<0,欠款=0 生成收款单、收费明细（已结算）
             * 7、已收<0,欠款<0 生成收款单、收费明细（部分结算）
             * 7、已收<0,欠款>0 生成收款单、收费明细（负）（已结算）、收费明细（正）（未结算）
             */

            //已收款金额
            BigDecimal receivableAmount = omsOutbound.getPaymentAmount();
            //欠款金额
            BigDecimal owedAmount = omsOutbound.getOwedAmount();
            //生成收款明细
            OmsReceivableDetail omsReceivableDetail = new OmsReceivableDetail();
            omsReceivableDetail.setCode(IdUtil.simpleUUID());
            //没有已收金额，应收明细为未结算
            if (receivableAmount.compareTo(BigDecimal.ZERO) == 0) {
                omsReceivableDetail.setStatus(SettlementStatusEnum.UNSETTLED);
                //收款明细总金额=欠款金额
            } else {
                //有已收金额，欠款等于0，应收明细为已结算
                if (owedAmount.compareTo(BigDecimal.ZERO) == 0) {
                    omsReceivableDetail.setStatus(SettlementStatusEnum.SETTLED);
                }
                //有已收金额，欠款金额大于0，应收明细为部分结算
                if (owedAmount.compareTo(BigDecimal.ZERO) != 0) {
                    omsReceivableDetail.setStatus(SettlementStatusEnum.PARTIALLY_SETTLED);
                }

            }

            omsReceivableDetail.setSourceCode(sourceCode);
            omsReceivableDetail.setShipmentCode(omsOutbound.getShipmentCode());
            omsReceivableDetail.setShipmentName(omsOutbound.getShipmentName());
            omsReceivableDetail.setBillType(OmsOutboundTypeEnum.getEnumByValue(omsOutbound.getType()));
            omsReceivableDetail.setGmtBill(omsOutbound.getGmtCreated().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            omsReceivableDetail.setCustomerCode(customerCode);
            omsReceivableDetail.setCustomerName(customer.getName());
            //收款明细总金额=付款金额+欠款金额
            omsReceivableDetail.setAmountMoney(omsOutbound.getOwedAmount().add(omsOutbound.getPaymentAmount()));
            omsReceivableDetail.setSettledMoney(BigDecimalUtil.getNumber(omsOutbound.getPaymentAmount()));
            omsReceivableDetail.setWaitingSettledMoney(BigDecimal.ZERO);
            omsReceivableDetail.setUnsettledMoney(BigDecimalUtil.getNumber(owedAmount));
            omsReceivableDetail.setAmountMoney(BigDecimalUtil.getNumber(omsReceivableDetail.getAmountMoney()));

            omsReceivableDetailService.save(omsReceivableDetail);





            //已收款，生成收款单和收款明细
            if (receivableAmount.compareTo(BigDecimal.ZERO) != 0) {
                OmsReceivable omsReceivable = new OmsReceivable();
                omsReceivable.setCode(OrderIdGeneratorUtil.generatorOrderId(OrderIdGeneratorUtil.OrderTypeEnum.SK, "", OrderIdPrefixEnum.OMS,UserUtil.getBranchCode()));
                omsReceivable.setShipmentCode(omsOutbound.getShipmentCode());
                omsReceivable.setShipmentName(omsOutbound.getShipmentName());
                omsReceivable.setCustomerCode(customerCode);
                omsReceivable.setCustomerName(customer.getName());
                omsReceivable.setAmountMoney(BigDecimalUtil.getNumber(receivableAmount));
                omsReceivable.setStatus(PASS);
                omsReceivable.setGmtVerify(LocalDateTime.now());
                omsReceivable.setCreatedBy(UserUtil.getCode());
                omsReceivable.setCreatedName(partyCache.translate(UserUtil.getCode()));
                omsReceivable.setModifiedBy(UserUtil.getCode());
                omsReceivable.setModifiedName(partyCache.translate(UserUtil.getCode()));
                omsReceivableService.save(omsReceivable);

                //收款单明细
                OmsReceivableItem omsReceivableItem = new OmsReceivableItem();
                omsReceivableItem.setCode(IdUtil.simpleUUID());
                omsReceivableItem.setSourceCode(omsOutbound.getSourceCode());
                omsReceivableItem.setReceivableDetailCode(omsReceivableDetail.getCode());
                omsReceivableItem.setReceivableCode(omsReceivable.getCode());
                omsReceivableItem.setShipmentCode(omsOutbound.getShipmentCode());
                omsReceivableItem.setShipmentName(omsOutbound.getShipmentName());
                omsReceivableItem.setBillType(OmsOutboundTypeEnum.getEnumByValue(omsOutbound.getType()));
                omsReceivableItem.setGmtBill(omsOutbound.getGmtCreated().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
                omsReceivableItem.setCustomerCode(customerCode);
                omsReceivableItem.setCustomerName(customer.getName());
                //收款明细总金额=收款金额+欠款金额
                omsReceivableItem.setAmountMoney(BigDecimalUtil.getNumber(omsReceivableDetail.getAmountMoney()));
                omsReceivableItem.setSettledMoney(BigDecimal.ZERO);
                //本次结算金额=付款金额
                omsReceivableItem.setThisSettledMoney(BigDecimalUtil.getNumber(receivableAmount));
                omsReceivableItemService.save(omsReceivableItem);
            }
        }
    }






    /**
     * 生成收款结算单
     * 按客户分组生成多条结算单
     *
     * @param settlementDTO 费用明细code
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void receivableSettlement(final ExpenseDetailSettlementDTO settlementDTO) {

        //要结算的应收明细
        List<ExpenseDetailSettlementDTO.SettlementItem> items = settlementDTO.getSettlementItems();
        if (IterUtil.isEmpty(items)) {
            log.error("结算费用明细为空");
            throw new ServiceException("结算费用明细为空");
        }
        //当前用户code
        String userCode = UserUtil.getCode();
        //当前用户名称
        String userName = partyCache.translate(UserUtil.getCode());
        //当前用户所属企业code
        String shipmentCompanyCode = UserUtil.getShipmentCompanyCode();
        //当前用户所属企业name
        String shipmentCompanyName = UserUtil.getShipmentCompanyName();

        //要结算的应收明细CODE
        List<String> codes = items.stream().map(ExpenseDetailSettlementDTO.SettlementItem::getCode).collect(Collectors.toList());

        //获取要结算的应收明细信息
        List<OmsReceivableDetail> omsReceivableDetails = omsReceivableDetailService
                .list(new QueryWrapper<OmsReceivableDetail>().lambda()
                        .in(OmsReceivableDetail::getCode, codes)
                        .eq(OmsReceivableDetail::getShipmentCode, UserUtil.getShipmentCompanyCode())
                        .ne(OmsReceivableDetail::getStatus, ExpenseDetailStatusEnum.SETTLED));
        //按照客户分组
        Map<String, List<OmsReceivableDetail>> map = omsReceivableDetails.stream().collect(Collectors.groupingBy(OmsReceivableDetail::getCustomerCode));
        // 遍历生成多条结算单
        List<OmsReceivable> omsReceivables = map.entrySet().parallelStream().map(entry -> {

            Map<String, Object> customerMap = customerCache.get(entry.getKey());
            if (MapUtil.isEmpty(customerMap)) {
                log.error("找不到客户信息，无法结算");
                throw new ServiceException("找不到客户信息，无法结算");
            }
            int isSettlement = MapUtil.getInt(customerMap, "isSettlement");
            if (isSettlement == 0) {
                log.error("客户【{}】未设置结算，无法结算",MapUtil.getStr(customerMap,"name"));
                throw new ServiceException("客户【"+MapUtil.getStr(customerMap,"name")+"】未设置结算，无法结算");
            }


            OmsReceivable omsReceivable = new OmsReceivable();
            omsReceivable.setCode(OrderIdGeneratorUtil.generatorOrderId(OrderIdGeneratorUtil.OrderTypeEnum.SK, "", OrderIdPrefixEnum.OMS,UserUtil.getBranchCode()));
            omsReceivable.setShipmentCode(shipmentCompanyCode);
            omsReceivable.setShipmentName(shipmentCompanyName);
            omsReceivable.setCustomerCode(entry.getKey());
            omsReceivable.setCustomerName(customerCache.translate(entry.getKey()));
            omsReceivable.setStatus(NEWS);
            omsReceivable.setCreatedBy(userCode);
            omsReceivable.setCreatedName(userName);
            omsReceivable.setModifiedBy(userCode);
            omsReceivable.setModifiedName(userName);


            //结算应收费用明细
            List<OmsReceivableDetail> list = entry.getValue();
            //应收费用明细转成收款单明细
            List<OmsReceivableItem> omsReceivableItems = list.parallelStream().map(r -> {
                OmsReceivableItem item = new OmsReceivableItem();
                BeanUtil.copyProperties(r, item, false);
                item.setCode(IdUtil.simpleUUID());
                item.setReceivableCode(omsReceivable.getCode());
                item.setReceivableDetailCode(r.getCode());
                ExpenseDetailSettlementDTO.SettlementItem settlementItem = items.stream().filter(i -> StrUtil.equals(i.getCode(), r.getCode())).findFirst().orElse(null);
                if (settlementItem == null) {
                    log.error("找不到结算明细，无法设置结算金额");
                    throw new ServiceException("找不到结算明细");
                }
                item.setThisSettledMoney(settlementItem.getThisSettledMoney());
                return item;
            }).collect(Collectors.toList());

            //计算收款金额
            if (IterUtil.isNotEmpty(omsReceivableItems)) {
                BigDecimal amountCollected = omsReceivableItems.stream().map(OmsReceivableItem::getThisSettledMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
                omsReceivable.setAmountMoney(BigDecimalUtil.getNumber(amountCollected));
            }
            omsReceivable.setOmsReceivableItems(omsReceivableItems);
            return omsReceivable;
        }).collect(Collectors.toList());
        //创建结算单
        saveOmsReceivable(omsReceivables);
        //更新应收费用待结算金额，收款单审核后更新费用结算状态
        items.forEach(e -> {
            omsReceivableDetailService.updateSettlementMoney(e.getCode(), BigDecimalUtil.getNumber(e.getThisSettledMoney()), UserUtil.getCode(), partyCache.translate(UserUtil.getCode()));
        });

    }

    /**
     * 生成付款结算单
     * 按供应商分组生成多条结算单
     *
     * @param settlementDTO 结算费用
     */
    @Override
    public void payableSettlement(ExpenseDetailSettlementDTO settlementDTO) {

        //要结算的应付明细
        List<ExpenseDetailSettlementDTO.SettlementItem> items = settlementDTO.getSettlementItems();
        if (IterUtil.isEmpty(items)) {
            log.error("结算费用明细为空");
            throw new ServiceException("结算费用明细为空");
        }
        //当前用户code
        String userCode = UserUtil.getCode();
        //当前用户名称
        String userName = partyCache.translate(UserUtil.getCode());
        //当前用户所属企业code
        String shipmentCompanyCode = UserUtil.getShipmentCompanyCode();
        //当前用户所属企业name
        String shipmentCompanyName = UserUtil.getShipmentCompanyName();

        //要结算的应收明细CODE
        List<String> codes = items.stream().map(ExpenseDetailSettlementDTO.SettlementItem::getCode).collect(Collectors.toList());

        //获取要结算的应收明细信息
        List<OmsPayableDetail> omsReceivableDetails = omsPayableDetailService
                .list(new QueryWrapper<OmsPayableDetail>().lambda()
                        .in(OmsPayableDetail::getCode, codes)
                        .eq(OmsPayableDetail::getShipmentCode, UserUtil.getShipmentCompanyCode())
                        .ne(OmsPayableDetail::getStatus, ExpenseDetailStatusEnum.SETTLED));
        //按照客户分组
        Map<String, List<OmsPayableDetail>> map = omsReceivableDetails.stream().collect(Collectors.groupingBy(OmsPayableDetail::getSupplierCode));
        // 遍历生成多条结算单
        List<OmsPayable> omsPayables = map.entrySet().parallelStream().map(entry -> {

            Map<String, Object> supplierMap = supplierCache.get(entry.getKey());
            if (MapUtil.isEmpty(supplierMap)) {
                log.error("找不到供应商信息，无法结算");
                throw new ServiceException("找不到供应商信息，无法结算");
            }
            int isSettlement = MapUtil.getInt(supplierMap, "isSettlement");
            if (isSettlement == 0) {
                log.error("供应商【{}】未设置结算，无法结算",MapUtil.getStr(supplierMap,"name"));
                throw new ServiceException("供应商【"+MapUtil.getStr(supplierMap,"name")+"】未设置结算，无法结算");
            }


            OmsPayable omsPayable = new OmsPayable();
            omsPayable.setCode(OrderIdGeneratorUtil.generatorOmsOrderId(OrderIdGeneratorUtil.OrderTypeEnum.FK, "",UserUtil.getBranchCode()));
            omsPayable.setShipmentCode(shipmentCompanyCode);
            omsPayable.setShipmentName(shipmentCompanyName);
            omsPayable.setSupplierCode(entry.getKey());
            omsPayable.setSupplierName(MapUtil.getStr(supplierMap,"name"));
            omsPayable.setStatus(NEWS);
            omsPayable.setCreatedBy(userCode);
            omsPayable.setCreatedName(userName);
            omsPayable.setModifiedBy(userCode);
            omsPayable.setModifiedName(userName);


            //结算应付费用明细
            List<OmsPayableDetail> list = entry.getValue();
            //应付费用明细转成收款单明细
            List<OmsPayableItem> omsPayableItems = list.parallelStream().map(r -> {
                OmsPayableItem item = new OmsPayableItem();
                BeanUtil.copyProperties(r, item, false);
                item.setCode(IdUtil.simpleUUID());
                item.setPayableCode(omsPayable.getCode());
                item.setPayableDetailCode(r.getCode());
                ExpenseDetailSettlementDTO.SettlementItem settlementItem = items.stream().filter(i -> StrUtil.equals(i.getCode(), r.getCode())).findFirst().orElse(null);
                if (settlementItem == null) {
                    log.error("找不到结算明细，无法设置结算金额");
                    throw new ServiceException("找不到结算明细");
                }
                item.setThisSettledMoney(settlementItem.getThisSettledMoney());
                return item;
            }).collect(Collectors.toList());

            //计算收款金额
            if (IterUtil.isNotEmpty(omsPayableItems)) {
                BigDecimal amountCollected = omsPayableItems.stream().map(OmsPayableItem::getThisSettledMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
                omsPayable.setAmountMoney(BigDecimalUtil.getNumber(amountCollected));
            }
            omsPayable.setOmsPayableItems(omsPayableItems);
            return omsPayable;
        }).collect(Collectors.toList());
        //创建结算单
        saveOmsPayable(omsPayables);
        //更新应收费用待结算金额，收款单审核后更新费用结算状态
        items.forEach(e -> {
            omsPayableDetailService.updateSettlementMoney(e.getCode(), BigDecimalUtil.getNumber(e.getThisSettledMoney()), UserUtil.getCode(), partyCache.translate(UserUtil.getCode()));
        });

    }

    /**
     * 保存收款单
     *
     * @param omsReceivables
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public boolean saveOmsReceivable(List<OmsReceivable> omsReceivables) {
        omsReceivableService.saveBatch(omsReceivables);
        omsReceivables.parallelStream().forEach(r -> {
            omsReceivableItemService.saveBatch(r.getOmsReceivableItems());
        });
        return true;
    }

    /**
     * 保存收款单
     *
     * @param omsPayables
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public boolean saveOmsPayable(List<OmsPayable> omsPayables) {
        omsPayableService.saveBatch(omsPayables);
        omsPayables.parallelStream().forEach(r -> {
            omsPayableItemService.saveBatch(r.getOmsPayableItems());
        });
        return true;
    }
}
